package euler.helper;

import java.math.BigInteger;

public class BigRational {

	private static final PrimeHelper primeHelper = new PrimeHelper();
    public static final BigRational ZERO = new BigRational(BigInteger.ZERO, BigInteger.ONE);
    public static final BigRational UNO = new BigRational(BigInteger.ONE, BigInteger.ONE);
    public static final BigRational DOS = new BigRational(BigInteger.valueOf(2), BigInteger.ONE);

    private final BigInteger num;
    private final BigInteger denum;

    public BigRational(BigInteger num, BigInteger denum) {
        if (denum.signum() == 0) {
            throw new ArithmeticException("Division by zero");
        }

        if (num.signum() == 0) {
            num = BigInteger.ZERO;
            denum = BigInteger.ONE;
        } else if (denum.signum() < 0){
            num = num.negate();
            denum = denum.negate();
        }

        BigInteger mcd;
        if (num.signum() < 0) {
            mcd = primeHelper.MCD(num.negate(), denum);
        } else if (num.signum() > 0) {
            mcd = primeHelper.MCD(num, denum);
        } else {
            mcd = BigInteger.ONE;
        }

        this.num = num.divide(mcd);
        this.denum = denum.divide(mcd);
    }

    public BigInteger getNum() {
        return this.num;
    }

    public BigInteger getDenum() {
        return this.denum;
    }

    public BigRational inverso() {
        if (this.num.signum() == 0) {
            throw new ArithmeticException("Division by zero");
        }

        return new BigRational(this.denum, this.num);
    }

    public BigRational producto(BigRational op) {

        if (this.num.signum()  == 0 || op.num.signum() == 0) {
            return ZERO;
        }

        BigInteger nuevoNum = this.num.multiply(op.num);
        BigInteger nuevoDenum = this.denum.multiply(op.denum);

        return new BigRational(nuevoNum, nuevoDenum);
    }

    public BigRational negado() {
        return new BigRational(this.num.negate(), this.denum);
    }

    public BigRational suma(BigRational op) {
        BigInteger nuevoNum = this.num.multiply(op.denum).add(this.denum.multiply(op.num));
        BigInteger nuevoDenum = this.denum.multiply(op.denum);

        return new BigRational(nuevoNum, nuevoDenum);
    }

    @Override
    public String toString() {
        if (this.denum.equals(BigInteger.ONE)) {
            return String.valueOf(this.num);
        } else {
            return String.valueOf(this.num) + '/' + String.valueOf(this.denum);
        }
    }

    public BigRational resta(BigRational op) {
        return this.suma(op.negado());
    }

    public BigRational division(BigRational op) {
        return this.producto(op.inverso());
    }
}
